﻿using FastBuild.TimeJob;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
using SqlSugar;
using System.Net.Http;
using System.Security.Policy;
using System.Text.RegularExpressions;
using Wechat_PublicNumber.Common;
using Wechat_PublicNumber.Entity;
using Wechat_PublicNumber.Model.Input.PublicNumberPushTemplate;
using Wechat_PublicNumber.Repository;

namespace Wechat_PublicNumber.Jobs
{
    /// <summary>
    /// 股票预警
    /// </summary>
    [SkipWhileExecuting]
    public class StockWarningJob : DataAccess, IJob
    {
        [Autowired]
        private CommonHttpInvoke _commonHttpInvoke;

        [Autowired]
        private WxTemplateRepository _templateRepository;

        [Autowired]
        private WxHttpInvoke _wxHttpInvoke;

        [Autowired]
        private IHttpClientFactory _httpClientFactory;

        public async Task Execute()
        {
            var nowTime = DateTime.Now;

#if RELEASE
                //非股票交易时间
                if (!StockTime.OpeningQuotation || nowTime < StockTime.MorningBeginTime
                        || (nowTime > StockTime.MorningEndTime && nowTime < StockTime.NoonBeginTime)
                        || nowTime > StockTime.NoonEndTime)
                    return;
#endif

            //获取所有人的设置列表
            var allSet = await WXDb.Queryable<UserStock, Stock, UserInfo>((us, stock, users) => new object[]
               {
                          JoinType.Inner, stock.ID== us.StockID,
                          JoinType.Inner, users.OpenID== us.OpenID
               })
             .Distinct()
             .Select((us, stock, users) => new
             {
                 stock.ID,
                 stock.StockName,
                 stock.StockCode,
                 stock.BelongStockExchange,
                 us.OpenID,
                 us.RemindChg,
                 us.RemindPercent,
                 us.RemindPrice
             })
             .ToListAsync();

            //获取所有股票
            var allStockCode = allSet.Select(s => s.BelongStockExchange + s.StockCode).Distinct().ToList();
            if (allStockCode.Count <= 0) return;

            var realStockList = await _commonHttpInvoke.GetRealTimeStock(allStockCode);

            foreach (var item in realStockList)
            {
                var oneStockUserList = allSet.Where(s => (s.BelongStockExchange + s.StockCode) == item.symbol).ToList();

                //预先载入模板所需参数
                var remaidParm = new StockWarningTemplateInput
                {
                    stockName = $"{oneStockUserList[0].StockName}({item.symbol})",
                    stockprice = item.current,
                    stockchg = item.chg,
                    stockpercent = item.percent
                };

                //偏移量 百分之0.15
                var offsetPercent = 0.15M;
                var offset = item.current * offsetPercent / 100;//价格和涨跌值不是百分比，所以要/100算出偏移量

                //提醒股票价格到了
                //提醒涨跌幅到了
                //提醒涨跌幅百分比到了
                var pushOpenIDList = oneStockUserList.Where(one =>
                        (item.current != 0 && one.RemindPrice != 0 && item.current.BetweenOffset(one.RemindPrice, offset))
                     || (item.chg != 0 && one.RemindChg != 0 && item.chg.BetweenOffset(one.RemindChg, offset))
                     //涨跌百分比已经是百分比了 所以offsetPercent*100
                     || (item.percent != 0 && one.RemindPercent != 0 && item.percent.BetweenOffset(one.RemindPercent, offsetPercent))
                     ).Select(one => one.OpenID).Distinct().ToList();

                //频率限制 每人每个股票5分钟推送一次
                pushOpenIDList = await FilterFrequency(oneStockUserList[0].ID, pushOpenIDList);

                //推送模板
                var pushData = await _templateRepository.GetTemplateData(Model.WeChatTemplateEnum.StockWarning, pushOpenIDList, remaidParm);
                if (pushData is not null)
                {
                    await _wxHttpInvoke.PushTemplate(pushData);
                    await WXDb.Insertable(pushData.Select(s => new StockMonitorHistory()
                    {
                        OpenID = s.touser,
                        CreateTime = DateTime.Now,
                        StockID = oneStockUserList[0].ID
                    }).ToList()).ExecuteCommandAsync();
                }
            }

            _logger.Info($"StockWarningJob Successfully executed", "StockWarningJob");

        }

        private async Task<List<string>> FilterFrequency(long stockID, List<string> openID)
        {
            return await WXDb.Queryable<UserStock, StockMonitorHistory>((us, sh) => new object[]
             {
                JoinType.Left,us.OpenID==sh.OpenID && us.StockID==sh.StockID
             })
             .Where((us, sh) => us.StockID == stockID && openID.Contains(us.OpenID))
             .GroupBy((us, sh) => us.OpenID)
             .Select((us, sh) => new
             {
                 us.OpenID,
                 MaxCreateTime = SqlFunc.AggregateMax(sh.CreateTime)
             })
             .MergeTable()
             .Where(s => s.MaxCreateTime.AddMinutes(5) <= DateTime.Now || SqlSugarExternalFucMethod.ISNull("MaxCreateTime"))
             .Select(s => s.OpenID)
             .ToListAsync();
        }
    }
}
